﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SimpleCsv
{
    public static class Csv
    {

        #region Reading
        
        /// <summary>
        /// Read CSV rows (list of string fields)
        /// </summary>
        /// <param name="inStream"></param>
        /// <param name="delimiterChar"></param>
        /// <param name="quoteChar"></param>
        /// <param name="leaveOpen">if true, does not close the stream when done reading</param>
        /// <returns></returns>
        public static IEnumerable<CsvRow> Read(StreamReader inStream,
            char delimiterChar = ',', char quoteChar = '"', bool leaveOpen = false)
        {
            using (var csv = new CsvReader(inStream, delimiterChar, quoteChar, leaveOpen))
            {
                while (true)
                {
                    CsvRow row = csv.ReadRow();
                    // End of stream
                    if (row == null) { break; }
                    yield return row;
                }
            }
        }

        /// <summary>
        /// Read CSV rows (list of string fields)
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="inStream"></param>
        /// <param name="delimiterChar"></param>
        /// <param name="quoteChar"></param>
        /// <returns></returns>
        public static IEnumerable<CsvRow> Read(String filename,
            char delimiterChar = ',', char quoteChar = '"')
        {
            StreamReader sr = new StreamReader(filename);
            // Stream will be closed after iteration is done
            return Read(sr, delimiterChar, quoteChar);
        }

        #endregion

        #region Writing

        /// <summary>
        /// Write CSV file from CSV rows (list of strings)
        /// </summary>
        /// <param name="outStream"></param>
        /// <param name="rows"></param>
        /// <param name="delimiterChar"></param>
        /// <param name="quoteChar"></param>
        /// <param name="leaveOpen"></param>
        public static void Write(StreamWriter outStream, IEnumerable<CsvRow> rows,
            char delimiterChar = ',', char quoteChar = '"', bool leaveOpen = false)
        {
            using (var csv = new CsvWriter(outStream, delimiterChar, quoteChar, leaveOpen))
            {
                foreach (CsvRow row in rows)
                {
                    csv.WriteRow(row);
                }
            }
        }

        // Filename
        public static void Write(String filename, IEnumerable<CsvRow> rows,
            char delimiterChar = ',', char quoteChar = '"')
        {
            StreamWriter sw = new StreamWriter(filename);
            Write(sw, rows, delimiterChar, quoteChar);
        }

        // LINQ
        public static IEnumerable<CsvRow> WriteCsv(this IEnumerable<CsvRow> rows, StreamWriter outStream,
            char delimiterChar = ',', char quoteChar = '"', bool leaveOpen = false)
        {
            Write(outStream, rows, delimiterChar, quoteChar, leaveOpen);
            return rows;
        }

        // Filename, LINQ
        public static IEnumerable<CsvRow> WriteCsv(this IEnumerable<CsvRow> rows, String filename, 
            char delimiterChar = ',', char quoteChar = '"')
        {
            Write(filename, rows, delimiterChar, quoteChar);
            return rows;
        }

        #endregion

        #region Appending

        // Filename
        public static void AppendRow(String filename, CsvRow row,
            char delimiterChar = ',', char quoteChar = '"')
        {
            var sw = new StreamWriter(filename, true, Encoding.Default); 
            using (var csv = new CsvWriter(sw , delimiterChar, quoteChar))
            {
                csv.WriteRow(row);
            }
        }

        #endregion

        #region Encoding

        public static String EncodeRow(IEnumerable<String> row,
                char delimiterChar = ',', char quoteChar = '"')
        {
            return CsvWriter.EncodeRow(row, delimiterChar, quoteChar);
        }

        public static CsvRow DecodeRow(String rowStr,
                char delimiterChar = ',', char quoteChar = '"')
        {
            return CsvReader.DecodeRow(rowStr, delimiterChar, quoteChar);
        }

        #endregion
    }
}
